package cn.org.itool.ws.framework.protocol.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import cn.org.itool.ws.framework.constent.WsProtocolEnum;
import cn.org.itool.ws.framework.netty.message.*;
import cn.org.itool.ws.framework.protocol.pomelo.Protocol;
import cn.org.itool.ws.framework.protocol.service.ProtocolService;
import cn.org.itool.ws.framework.ws.WsServer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import lombok.extern.log4j.Log4j2;

import java.util.ArrayList;
import java.util.List;

@Log4j2
public class ProtocolPomeloServiceImpl extends ProtocolService {

    @Override
    public WsProtocolEnum type() {
        return WsProtocolEnum.POMELO;
    }

    @Override
    public List<BizWsPackage> decodePackage(Object text) {
        ByteBuf buf = (ByteBuf)text;

        byte[] buffer;
        int offset = 0;
        if(buf.hasArray()) { // 处理堆缓冲区
            buffer = buf.array();
            offset = buf.arrayOffset() + buf.readerIndex();
        } else { // 处理直接缓冲区以及复合缓冲区
            buffer = new byte[buf.readableBytes()];
            buf.getBytes(buf.readerIndex(), buffer);
        }

        List<Protocol.Package.PackageType> list = Protocol.Package.decode(buffer, offset);

        List<BizWsPackage> packageList = new ArrayList<>();
        for (Protocol.Package.PackageType type : list) {
            BizWsPackage bizWsPackage = new BizWsPackage();
            bizWsPackage.setType(type.getType());
            bizWsPackage.setBody(type.getBody());

            packageList.add(bizWsPackage);
        }

        return packageList;
    }

    @Override
    public BizWsMessage decodeMessage(Object body) {
        Protocol.Message message = Protocol.Message.decode((byte[]) body);
        BizWsMessage websocketMessage = new BizWsMessage();
        websocketMessage.setId(message.getId());
        websocketMessage.setType(message.getType());
        websocketMessage.setRoute(message.getRoute());
        websocketMessage.setCompressRoute(message.getCompressRoute() != 0);
        websocketMessage.setCompressGzip(message.getCompressGzip() != 0);
        String str = Protocol.strDecode(message.getBody());
        websocketMessage.setBody(str);

        log.info("decodeMessage:router:{}", websocketMessage.getRoute());

        return websocketMessage;
    }

    @Override
    public Object encode(WsHandShake resp) {
        String resStr = Protocol.strDecode((byte[]) resp.getMessageByte());
        JSONObject data = JSON.parseObject(resStr);
        data.put("code", 200);
        JSONObject sys = new JSONObject();
        sys.put("heartbeat", WsServer.NETTY_PROPERTIES.getHeartbeat());
        data.put("sys", sys);

        byte[] msgByteArr = Protocol.strEncode(data.toString());
        return new BinaryWebSocketFrame(Unpooled.wrappedBuffer(Protocol.Package.encode(Protocol.Package.TYPE_HANDSHAKE, msgByteArr)));
    }

    @Override
    public Object encode(WsHandShakeAck resp) {
        return new BinaryWebSocketFrame(Unpooled.wrappedBuffer(Protocol.Package.encode(Protocol.Package.TYPE_HEARTBEAT, null)));
    }

    @Override
    public Object encode(WsHeartbeat resp) {
        return new BinaryWebSocketFrame(Unpooled.wrappedBuffer(Protocol.Package.encode(Protocol.Package.TYPE_HEARTBEAT, null)));
    }

    @Override
    public Object encode(BizWsMessage websocketMessage) {
        try {

            byte[] msgByteArr = Protocol.Message.encode(
                    websocketMessage.getId(),
                    websocketMessage.getType(),
                    websocketMessage.getCompressRoute(),
                    websocketMessage.getRoute(),
                    Protocol.strEncode(WsServer.OBJECT_MAPPER.writeValueAsString(websocketMessage.getBody())),
                    websocketMessage.getCompressGzip()
            );

            return new BinaryWebSocketFrame(Unpooled.wrappedBuffer(Protocol.Package.encode(Protocol.Package.TYPE_DATA, msgByteArr)));
        }catch (Exception e) {
            log.error("e:", e);
        }
        return null;
    }
}
